package http

import (
	stdContext "context"
	"cyiris/core/protocol"
	log "cyiris/core/zaplog"
	"fmt"
	"time"

	"github.com/kataras/iris/v12"
)

type HttpServer interface {
	Start()
	RegisterRouter(string, string, Ctrl)
	HandlerFunc(ctrl Ctrl) func(ctx iris.Context)
	App() *iris.Application
}

type httpServer struct {
	app        *iris.Application
	ServerHost string
}

func NewHttpServer(host string) HttpServer {
	return &httpServer{iris.New(), host}
}

func (srv *httpServer) Start() {
	// 注册错误处理逻辑
	srv.app.OnErrorCode(iris.StatusNotFound, notFound)
	srv.app.OnErrorCode(iris.StatusInternalServerError, internalServerError)

	idleConnsClosed := make(chan struct{})
	iris.RegisterOnInterrupt(func() {
		timeout := 10 * time.Second
		ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
		defer cancel()
		srv.app.Shutdown(ctx)
		close(idleConnsClosed)
	})

	srv.app.Run(iris.Addr(srv.ServerHost), iris.WithoutInterruptHandler)
	<-idleConnsClosed
}

func (srv *httpServer) App() *iris.Application {
	return srv.app
}

/**
 * 注册路由处理程序
 */
func (srv *httpServer) RegisterRouter(method string, uri string, ctrl Ctrl) {
	srv.app.Handle(method, uri, srv.HandlerFunc(ctrl))
}

/**
 * 路由处理逻辑函数
 */
func (srv *httpServer) HandlerFunc(ctrl Ctrl) func(ctx iris.Context) {
	return func(ctx iris.Context) {
		myctx := NewContext(ctx)
		defer func() {
			if err := recover(); err != nil {
				srv.handleError(myctx, err)
			}
		}()
		srv.ctrlAction(ctrl, myctx)
	}
}

func (srv *httpServer) ctrlAction(ctrl Ctrl, ctx *Context) {
	// 执行 filter 定义的 DoBefore 函数
	filters := ctrl.Filters()
	for _, f := range filters {
		if err := f.DoBefore(ctx); err != nil {
			log.Warnf("Ctrl Before Filter Failed: %s", err)
			return
		}
	}

	// 执行控制器定义的前置函数
	if err := ctrl.DoBefore(ctx); err != nil {
		log.Warnf("Ctrl DoBefore Failed: %s", err)
		return
	}

	log.Debugf("exec ctrl %T Action", ctrl)
	ctrl.Action(ctx)

	// 执行控制器定义的后置函数
	if err := ctrl.DoAfter(ctx); err != nil {
		log.Warnf("Ctrl DoAfter Failed: %s", err)
		return
	}

	// 执行 filter 定义的 Dobefor 函数，后注册的先执行
	length := len(filters) - 1
	for i := range filters {
		f := filters[length-i]
		if err := f.DoAfter(ctx); err != nil {
			log.Warnf("Ctrl After Filter Failed: %s", err)
			return
		}
	}
}

func (srv *httpServer) handleError(ctx *Context, err interface{}) {
	// srv.ErrorHandler(ctx, err)
	// log.Errorf("Server Panic: %s", err)
	ctx.Values().Set("error", err)
	// ctx.EmitError(iris.StatusInternalServerError)
}

func notFound(ctx iris.Context) {
	response := protocol.Response{Code: protocol.NOT_FOUND, Msg: "Service Not Found"}
	ctx.JSON(response)
}

func internalServerError(ctx iris.Context) {
	response := protocol.Response{Code: protocol.SERVER_ERROR}
	err := ctx.Values().Get("error")
	if err != nil {
		response.Msg = fmt.Sprintf("%s", err)
	}
	ctx.JSON(response)
}
